package com.hgx.su.common.pure.util.coordinate;

/**
 * 坐标转换工具
 * <p>
 * 经过测试 误差在十万分之一左右
 * <p>
 * 各地图API坐标系统比较与转换;
 * WGS84坐标系：即地球坐标系，国际上通用的坐标系。设备一般包含GPS芯片或者北斗芯片获取的经纬度为WGS84地理坐标系,
 * 谷歌地图采用的是WGS84地理坐标系（中国范围除外）;
 * GCJ02坐标系：即火星坐标系，是由中国国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系。
 * 谷歌中国地图和搜搜中国地图采用的是GCJ02地理坐标系; BD09坐标系：即百度坐标系，GCJ02坐标系经加密后的坐标系;
 * 搜狗坐标系、图吧坐标系等，估计也是在GCJ02基础上加密而成的。
 * WGS-84 地心坐标系，即GPS原始坐标体系
 * GCJ-02火星坐标系，国测局02年发布的坐标体系，它是一种对经纬度数据的加密算法，即加入随机的偏差。高德、腾讯、Google中国地图使用。国内最广泛使用的坐标体系；
 * 一般都是由GCJ-02进过偏移算法得到的。这种体系就根据每个公司的不同，坐标体系都不一样了。
 * 比如，百度的BD-09坐标、搜狗坐标等
 */
public class CoordinateConversionUtils {

    private static final double pi = Math.PI;
    private static final double x_pi = Math.PI * 3000.0 / 180.0;
    private static final double a = 6378245.0;
    private static final double ee = 0.00669342162296594323;

    private static double transformLat(double x, double y) {
        double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
                + 0.2 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
        return ret;
    }

    private static double transformLon(double x, double y) {
        double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
                * Math.sqrt(Math.abs(x));
        ret += ((20.0 * Math.sin(6.0 * x * pi)) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0
                * pi)) * 2.0 / 3.0;
        return ret;
    }

    private static boolean outOfChina(double lat, double lon) {
        if (lon < 72.004 || lon > 137.8347)
            return true;
        return lat < 0.8293 || lat > 55.8271;
    }

    /**
     * 84 to 火星坐标系 (GCJ-02) World Geodetic System ==> Mars Geodetic System
     *
     * @param lat 纬度
     * @param lon 经度
     * @return 转换后坐标
     */
    public static double[] gps84ToGcj02(double lat, double lon) {
        if (outOfChina(lat, lon)) {
            return new double[]{lat, lon};
        }
        double dLat = transformLat(lon - 105.0, lat - 35.0);
        double dLon = transformLon(lon - 105.0, lat - 35.0);
        double radLat = lat / 180.0 * pi;
        double magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
        double mgLat = lat + dLat;
        double mgLon = lon + dLon;
        return new double[]{mgLat, mgLon};
    }

    /**
     * 火星坐标系 (GCJ-02) to 84
     *
     * @param lon 经度
     * @param lat 纬度
     * @return 转后坐标
     */
    public static double[] gcj02ToGps84(double lat, double lon) {
        double[] gps = gps84ToGcj02(lat, lon);
        double longitude = lon * 2 - gps[1];
        double latitude = lat * 2 - gps[0];
        return new double[]{latitude, longitude};
    }

    /**
     * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法
     * 将 GCJ-02 坐标转换成 BD-09 坐标
     *
     * @param lat 纬度
     * @param lon 经度
     * @return 转换后坐标
     */
    public static double[] gcj02ToBd09(double lat, double lon) {
        double z = Math.sqrt(lon * lon + lat * lat) + 0.00002 * Math.sin(lat * x_pi);
        double theta = Math.atan2(lat, lon) + 0.000003 * Math.cos(lon * x_pi);
        double tempLon = z * Math.cos(theta) + 0.0065;
        double tempLat = z * Math.sin(theta) + 0.006;
        return new double[]{tempLat, tempLon};
    }

    /**
     * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法
     * 将 BD-09 坐标转换成GCJ-02 坐标
     */
    public static double[] bdToGcj02(double lat, double lon) {
        double x = lon - 0.0065, y = lat - 0.006;
        double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
        double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
        double tempLon = z * Math.cos(theta);
        double tempLat = z * Math.sin(theta);
        return new double[]{tempLat, tempLon};
    }

    /**
     * 将gps84转为bd09
     *
     * @param lat 纬度
     * @param lon 经度
     * @return 转换后坐标
     */
    public static double[] gps84ToBd09(double lat, double lon) {
        double[] gcj02 = gps84ToGcj02(lat, lon);
        return gcj02ToBd09(gcj02[0], gcj02[1]);
    }

    public static double[] bd09ToGps84(double lat, double lon) {
        double[] gcj02 = bdToGcj02(lat, lon);
        double[] gps84 = gcj02ToGps84(gcj02[0], gcj02[1]);
        //保留小数点后六位
        gps84[0] = retain6(gps84[0]);
        gps84[1] = retain6(gps84[1]);
        return gps84;
    }

    /**
     * 保留小数点后六位
     *
     * @param num 经纬度
     * @return 保留值
     */
    private static double retain6(double num) {
        String result = String.format("%.6f", num);
        return Double.parseDouble(result);
    }

//    public static void main(String[] args) {
//
//        String[] opp = new String[]{"31.214811,107.45472" , "31.214806,107.454704" , "31.21402,107.454735" , "31.212656,107.45478" , "31.21126,107.45489" , "31.209463,107.45425" , "31.20817,107.45385" , "31.20752,107.45386" , "31.20575,107.45333" , "31.203432,107.45198" , "31.202532,107.45043" , "31.201786,107.449814" , "31.201797,107.4498" , "31.201546,107.450325" , "31.200727,107.45205" , "31.20124,107.45355" , "31.200686,107.454895" , "31.200592,107.4559" , "31.200567,107.45588" , "31.2007,107.45542" , "31.200459,107.45477" , "31.199734,107.45411" , "31.199894,107.453705" , "31.199871,107.4537" , "31.199928,107.45357" , "31.199928,107.45366" , "31.199926,107.4537" , "31.199903,107.45365" , "31.199896,107.45368" , "31.199903,107.453735" , "31.199924,107.45374" , "31.199903,107.45371" , "31.19988,107.45368" , "31.199852,107.45369" , "31.199848,107.45362" , "31.199812,107.45367" , "31.199844,107.453606" , "31.199877,107.45365" , "31.199903,107.45369" , "31.199907,107.45376" , "31.199926,107.45374" , "31.199911,107.45371" , "31.1999,107.45372" , "31.199936,107.453705" , "31.199957,107.45372" , "31.199991,107.45371" , "31.199984,107.45376" , "31.199965,107.453766" , "31.199944,107.453735" , "31.199892,107.45375" , "31.199898,107.4537" , "31.199863,107.45376" , "31.199875,107.45374" , "31.19988,107.45371" , "31.199871,107.45374" , "31.199907,107.45367" , "31.199917,107.4537" , "31.199894,107.45371" , "31.199877,107.453705" , "31.199871,107.45369" , "31.199863,107.45368" , "31.199867,107.45371" , "31.199877,107.4537" , "31.199892,107.45369" , "31.199892,107.45368" , "31.199879,107.45372" , "31.19986,107.45368" , "31.199867,107.45368" , "31.199863,107.45372" , "31.199884,107.45371" , "31.199894,107.45375" , "31.199898,107.45374" , "31.199894,107.45374" , "31.199892,107.45372" , "31.199892,107.45371" , "31.199892,107.453735" , "31.1999,107.45375" , "31.19992,107.45376" , "31.199896,107.45375" , "31.199905,107.45376" , "31.199905,107.453766" , "31.199951,107.45372" , "31.19992,107.45374" , "31.199915,107.453735" , "31.199894,107.45377" , "31.199903,107.453766" , "31.199905,107.45377" , "31.199903,107.45374" , "31.199884,107.453766" , "31.199892,107.45376" , "31.199907,107.45375" , "31.199944,107.45371" , "31.199926,107.45371" , "31.199915,107.45371" , "31.199907,107.4537" , "31.199875,107.45372" , "31.199867,107.45374" , "31.199905,107.45375" , "31.199907,107.453735" , "31.199894,107.453735" , "31.199911,107.45375" , "31.199911,107.45373" , "31.199917,107.45373" , "31.200306,107.45375" , "31.20124,107.45376" , "31.202486,107.45228" , "31.203638,107.45214" , "31.205439,107.453186" , "31.206867,107.45399" , "31.206867,107.45398" , "31.207,107.45399" , "31.207935,107.45398" , "31.2111,107.45503" , "31.213144,107.454926" , "31.214483,107.45421" , "31.214577,107.45379" , "31.21464,107.45328" , "31.214668,107.4529" , "31.214752,107.45228" , "31.214758,107.45216" , "31.21478,107.45214" , "31.21471,107.45213" , "31.214611,107.45285" , "31.214512,107.453575" , "31.214573,107.45373" , "31.214716,107.45261" , "31.214716,107.45196" , "31.214643,107.45252" , "31.214506,107.45325" , "31.214453,107.45382" , "31.214458,107.4539" , "31.214432,107.45443" , "31.214426,107.45447" , "31.214352,107.45568" , "31.21434,107.4562" , "31.21436,107.45635" , "31.214388,107.45706" , "31.214403,107.45877" , "31.214403,107.45968" , "31.21516,107.46029" , "31.217476,107.460655" , "31.219336,107.46125" , "31.218952,107.462685" , "31.218908,107.4631" , "31.218687,107.46441" , "31.219688,107.46496" , "31.22124,107.46596" , "31.221172,107.46622" , "31.221172,107.46644" , "31.221094,107.46722" , "31.219769,107.46667" , "31.218897,107.46572" , "31.218788,107.46545" , "31.218674,107.467224" , "31.218843,107.47278" , "31.218727,107.47277" , "31.218649,107.47524" , "31.217007,107.47702" , "31.217049,107.47699" , "31.217216,107.47872" , "31.217966,107.48386" , "31.218216,107.48814" , "31.218275,107.48984" , "31.218275,107.48981" , "31.218342,107.48989" , "31.218435,107.491486" , "31.218887,107.49301" , "31.21872,107.49448" , "31.2187,107.49463" , "31.218496,107.49563" , "31.218521,107.495705" , "31.218748,107.49486" , "31.218992,107.4935" , "31.218782,107.49204" , "31.218649,107.49126" , "31.218893,107.49215" , "31.218876,107.49283" , "31.218874,107.49284" , "31.21882,107.49286" , "31.218975,107.49285" , "31.218985,107.49339" , "31.2189,107.494026" , "31.218668,107.49508" , "31.218582,107.49543" , "31.218536,107.49562" , "31.218307,107.49659" , "31.218197,107.497406" , "31.217976,107.49835" , "31.217562,107.4999" , "31.21558,107.49962" , "31.215555,107.49963" , "31.215073,107.499275" , "31.21442,107.49969" , "31.212444,107.50102" , "31.210299,107.5024" , "31.208097,107.50379" , "31.205755,107.50394" , "31.203938,107.502014" , "31.20286,107.502174" , "31.2021,107.5057" , "31.201485,107.5075" , "31.198708,107.506065" , "31.19852,107.506035" , "31.198465,107.50598" , "31.198017,107.50743" , "31.19788,107.50867" , "31.198124,107.510414" , "31.197971,107.51114" , "31.197948,107.511185" , "31.197948,107.51138" , "31.2003,107.51165" , "31.202816,107.51417" , "31.206793,107.516426" , "31.21188,107.51818" , "31.216684,107.51925" , "31.220425,107.52075" , "31.223782,107.523224" , "31.224588,107.52037" , "31.22466,107.51986" , "31.224688,107.51959" , "31.225763,107.51502" , "31.224976,107.516914" , "31.224152,107.5171" , "31.222433,107.51644" , "31.222551,107.51653" , "31.224447,107.517204" , "31.227757,107.51734" , "31.231184,107.51558" , "31.232565,107.5153" , "31.234703,107.51506" , "31.234686,107.51498" , "31.234692,107.514984" , "31.234724,107.515" , "31.234684,107.515" , "31.234673,107.51502" , "31.234684,107.515015" , "31.234573,107.515015" , "31.234577,107.5151" , "31.234533,107.515114" , "31.234531,107.51508" , "31.234587,107.51509" , "31.234665,107.51502" , "31.234669,107.51499" , "31.234688,107.514984" , "31.234785,107.51493" , "31.234789,107.514984" , "31.234764,107.515" , "31.234755,107.51499" , "31.234497,107.515045" , "31.234476,107.51512" , "31.237135,107.514725" , "31.241598,107.514465" , "31.241592,107.51818" , "31.23946,107.52105" , "31.236244,107.522354" , "31.236296,107.52232" , "31.236565,107.52406" , "31.23606,107.527405" , "31.236149,107.52964" , "31.23604,107.531746" , "31.235434,107.5326" , "31.2346,107.534065" , "31.237968,107.537025" , "31.23754,107.54038" , "31.236305,107.54333" , "31.235607,107.5469" , "31.233747,107.55043" , "31.230871,107.55087" , "31.228737,107.55435" , "31.227028,107.55739" , "31.231775,107.55819" , "31.233706,107.56186" , "31.23406,107.56656" , "31.233614,107.57254" , "31.231808,107.5781" , "31.233273,107.582985" , "31.236671,107.58661" , "31.237724,107.59342" , "31.236055,107.59806" , "31.237724,107.60309" , "31.237589,107.606186" , "31.232203,107.609055" , "31.22712,107.615074" , "31.220987,107.61887" , "31.217104,107.62265" , "31.20287,107.66405" , "31.197308,107.66962" , "31.193336,107.676765" , "31.188068,107.68278" , "31.18334,107.68908" , "31.17888,107.69487" , "31.172676,107.69763" , "31.168571,107.70097" , "31.163733,107.706505" , "31.160856,107.70879" , "31.13574,107.74609" , "31.128847,107.748856" , "31.122366,107.75277" , "31.117111,107.75869" , "31.112768,107.76559" , "31.11038,107.77359" , "31.11061,107.78211" , "31.1087,107.79032" , "31.103724,107.79648" , "31.10105,107.79993" , "31.088894,107.81332" , "31.089333,107.816765" , "31.091608,107.81717" , "31.095392,107.81765" , "31.098703,107.819695" , "31.102217,107.82192" , "31.102736,107.82384" , "31.101145,107.82784" , "31.100285,107.83065" , "31.099407,107.83331" , "31.099253,107.83402" , "31.097944,107.838326" , "31.096603,107.842735" , "31.095247,107.84632" , "31.093859,107.84806" , "31.091146,107.85086" , "31.089993,107.854324" , "31.090069,107.855644" , "31.090038,107.85563" , "31.090199,107.856834" , "31.090334,107.8594" , "31.089031,107.86006" , "31.087849,107.86017" , "31.08512,107.860306" , "31.08422,107.86088" , "31.084436,107.86248" , "31.084476,107.862755" , "31.084509,107.86276" , "31.084993,107.86309" , "31.085459,107.863266" , "31.085093,107.8648" , "31.084612,107.86578" , "31.084505,107.86636" , "31.084145,107.867966" , "31.084593,107.86885"
//        };
//
//        Date startDate = new Date() ;
//        for (String s : opp) {
//            String[] uu = s.split(",");
//            String uu1 = uu[0];
//            String uu2 = uu[1];
//            double v = Double.parseDouble(uu1);
//            double v1 = Double.parseDouble(uu2);
//            double[] doubles = CoordinateConversionUtils.gps84ToGcj02(v, v1);
//            System.out.println(doubles[0] + "," + doubles[1]);
//        }
//        Date endDate = new Date() ;
//
//        System.out.println("--------------------------------");
//        System.out.println(opp.length);
//        System.out.println(startDate);
//        System.out.println(endDate);
//        System.out.println(endDate.getTime() - startDate.getTime());
//    }

}